#ifndef __LUAEX_H__
#define __LUAEX_H__

#include "utils/singleton.h"
#include "./luaobj.h"
#include "./luamodule.h"
#include "./luaclass.h"
#include "./luacaller.h"
#include "./luathread.h"
#include "./luafunctionregistration.h"

//[type]:luaobj
typedef RefObj<LuaObj> luaobj;

//[type]:luathread
typedef RefObj<LuaThread> luathread;

class LuaEx : public Singleton<LuaEx>
{
public:
	//static LuaEx& GetInstance()
	//{
	//	static LuaEx instance;
	//	return instance;
	//}

	LuaEx();
	~LuaEx();

	void SetLuaState(lua_State* luaState);
	lua_State* GetLuaState();

	template <class T>
	luaobj GetLuaObject(T* pObj)
	{
		luaobj obj;
		obj->InitObj(pObj);	
		return obj;
	}

	luaobj LoadFunc(const char* funcName);
	luathread NewThread();

	//use main thread state
	bool CallFunc(luaobj& funcobj);
	DEF_CALLERS

	bool CallThreadFunc(luathread& td, luaobj& funcobj);
	DEF_THREAD_CALLERS
private:
	bool CallFuncEx(lua_State* luaState, luaobj& funcobj);
	DEF_CALLEREXS

private:
	lua_State* m_luaState;
	luaobj m_nullObj;
};

//module
inline const LuaModule Def_Module(const char * name)
{
	return LuaModule(LuaEx::GetInstance().GetLuaState(), name);
}

//class
inline const LuaClass Def_Class(int classid)
{
	return LuaClass(LuaEx::GetInstance().GetLuaState(), classid);
}

//function
template <class F>
inline const Scope Def_Function(const char * name, F func)
{
	return Scope(new NormalFunctionRegistration<F>(name, func));
}

//wrapper_function
template <class F>
inline const Scope Def_Wrapper_Function(const char * name, F func)
{
	return Scope(new WrapperFunctionRegistration<F>(name, func));
}

//get_function
template <class F>
inline const Scope Def_Get_Function(const char * name, F func)
{
	return Scope(new GetFunctionRegistration<F>(name, func));
}

//lua_function
inline const Scope Def_Lua_Function(const char * name, lua_CFunction func)
{
	return Scope(new LuaFunctionRegistration(name, func));
}

//script
inline const Scope Def_Script(const char * script, const char * chunkname = NULL)
{
	return Scope(new ScriptRegistration(script, chunkname));
}

#endif